// EventsConfiguration.cpp

#include <sstream>

#include "Poco/DateTime.h"
#include "Poco/DateTimeParser.h"

#include "../include/EventsConfiguration.h"
#include <string>
using namespace Poco;
using namespace Poco::Util;
using namespace std;


// Constructor that receive data stream as std::istream
CEventsConfiguration::CEventsConfiguration(std::istream& istr) : IniFileConfiguration(istr)
{
        Construct();
}

// Constructor that receive path as std::string
CEventsConfiguration::CEventsConfiguration(const std::string& path) : IniFileConfiguration(path)
{
	cout<<"entering eventsconfig"<<endl;
	Construct();
}

std::vector<Events*>& CEventsConfiguration::getEvents(){
	return events;
}



CEventsConfiguration::~CEventsConfiguration()
{
	while (events.size() != 0){
		delete (events.back());
		events.pop_back();
	}
}

void CEventsConfiguration::Construct()
{

        // Reserve an initial size for my events vector,
        // so he can allocate in advance. If allocate
		ostringstream numOfEvents;
		numOfEvents <<"numberOfEvents" ;
		int num = getInt(numOfEvents.str());
		events.reserve(num);

        int currConfFileIndex = 1;
        bool quit = false;
        while (currConfFileIndex<=num)
        {
        	try
        	{
                	ostringstream typeKeyNameBuilder;


	                // Get event type

                	typeKeyNameBuilder << "EVENT" << currConfFileIndex<< ".Type";
	                string type = getString(typeKeyNameBuilder.str());

	                if (type == "create")
	                	readNcreateCreate(currConfFileIndex);
	                if (type == "consume")
	                	readNcreateConsume(currConfFileIndex);
	                if (type == "sell")
	                	readNcreateSell(currConfFileIndex);
	                if (type == "buy")
	                	readNcreateBuy(currConfFileIndex);
	                if (type == "userReport")
	                	readNcreateUserReport(currConfFileIndex);
	                if (type == "energyReport")
	                	readNcreateEnergyReport(currConfFileIndex);
	                if (type == "accountReport")
	                	readNcreateAccountReport(currConfFileIndex);
	                if (type == "profitReport")
	                	readNcreateProfitReport(currConfFileIndex);
	                if (type == "activityReport")
	                	readNcreateActivityReport(currConfFileIndex);

	                // 4. Increase event index
	                currConfFileIndex++;
        	}
        	catch (NotFoundException ex) {
				std::ostringstream strStream ;
				strStream << "Error reading events file.";
				EnergyMarketLogger::Instance().Log(strStream , Poco::Message::PRIO_CRITICAL);
				quit = true;
        	}
        }
}

void CEventsConfiguration::readNcreateCreate(int currConfFileIndex){
	bool isValid = false;

	ostringstream dateKeyNameBuilder;
	ostringstream userIdKeyNameBuilder;
	ostringstream energyTypeKeyNameBuilder;
	ostringstream numOfUnitsKeyNameBuilder;



	string dateStr = "";
	int id =0;
	string eType ="";
	string num="";
	try{
		// Get event date
		dateKeyNameBuilder << "EVENT" << currConfFileIndex<< ".Date";
		dateStr = getString(dateKeyNameBuilder.str());

		// Get event date
		userIdKeyNameBuilder << "EVENT" << currConfFileIndex<< ".UserID";
		id = getInt(userIdKeyNameBuilder.str());

		// Get event date
		energyTypeKeyNameBuilder << "EVENT" << currConfFileIndex<< ".EnergyType";
		eType = getString(energyTypeKeyNameBuilder.str());

		// Get event date
		numOfUnitsKeyNameBuilder << "EVENT" << currConfFileIndex<< ".NumberOfUnits";
		num = getString(numOfUnitsKeyNameBuilder.str());

		isValid = true;
	}
	catch (NotFoundException ex)
    {
    	cout << ex.displayText() << "\n";
    }

	// Parse the date
	DateTime* date = new Poco::DateTime();
	if (isValid){
		int timeZoneDiff;
		if (!DateTimeParser::tryParse("%d/%n/%Y", dateStr, *date, timeZoneDiff)){
			// Failed to parse date. quit.
			isValid = false;
		}

	}

	int intNum = atoi(num.c_str());

	ass2::eUser checkName = ass2::Id2eUser(id);
	ass2::eEnergy checkEnergy = ass2::stringToEnrgy(eType);
	if (checkName == ass2::eNoUser | checkEnergy == ass2::noEnergy){
		isValid = false;
	}

	string key = string();
	key = "EVENT";
	int i = currConfFileIndex;
	string s;
	stringstream out;
	out << i;
	s = out.str();
	key += s;
	Keys range = Keys();
	keys(key, range);
	if (range.size() > 5 | intNum <= 0)
		isValid = false;



	if (isValid){
		CreateEvent* event = new CreateEvent(date, id, ass2::stringToEnrgy(eType), intNum);
		events.push_back(event);
	}
	else{
		delete date;
	}

}
void CEventsConfiguration::readNcreateConsume(int currConfFileIndex){
	bool isValid = false;

	ostringstream dateKeyNameBuilder;
	ostringstream userIdKeyNameBuilder;
	ostringstream energyTypeKeyNameBuilder;
	ostringstream numOfUnitsKeyNameBuilder;
	//ostringstream priceKeyNameBuilder;

	string dateStr = "";
	string id ="";
	string eType ="";
	string num="";
	try{
		// Get event date
		dateKeyNameBuilder << "EVENT" << currConfFileIndex<< ".Date";
		dateStr = getString(dateKeyNameBuilder.str());

		// Get event date
		userIdKeyNameBuilder << "EVENT" << currConfFileIndex<< ".UserID";
		id = getString(userIdKeyNameBuilder.str());

		// Get event date
		energyTypeKeyNameBuilder << "EVENT" << currConfFileIndex<< ".EnergyType";
		eType = getString(energyTypeKeyNameBuilder.str());

		// Get event date
		numOfUnitsKeyNameBuilder << "EVENT" << currConfFileIndex<< ".NumberOfUnits";
		num = getString(numOfUnitsKeyNameBuilder.str());

		isValid = true;
	}
	catch (NotFoundException ex)
    {
    	cout << ex.displayText() << "\n";
    }

	// Parse the date
	DateTime* date = new Poco::DateTime();
	if (isValid){
		int timeZoneDiff;
		if (!DateTimeParser::tryParse("%d/%n/%Y", dateStr, *date, timeZoneDiff)){
			// Failed to parse date. quit.
			isValid = false;
		}

	}

	int intId = atoi(id.c_str());
	int intNum = atoi(num.c_str());


	ass2::eUser checkName = ass2::Id2eUser(intId);
	ass2::eEnergy checkEnergy = ass2::stringToEnrgy(eType);
	if (checkName == ass2::eNoUser | checkEnergy == ass2::noEnergy){
		isValid = false;
	}



	string key = string();
	key = "EVENT";
	int i = currConfFileIndex;
	string s;
	stringstream out;
	out << i;
	s = out.str();
	key += s;
	Keys range = Keys();
	keys(key, range);
	if (range.size() > 5 | intNum <=0)
		isValid = false;


	if (isValid){
	ConsumeEvent* event = new ConsumeEvent(date, intId, ass2::stringToEnrgy(eType), intNum);
	events.push_back(event);
	}
	else{
		delete date;
	}

}
void CEventsConfiguration::readNcreateSell(int currConfFileIndex){
	bool isValid = false;

	ostringstream dateKeyNameBuilder;
	ostringstream userIdKeyNameBuilder;
	ostringstream energyTypeKeyNameBuilder;
	ostringstream numOfUnitsKeyNameBuilder;
	ostringstream priceKeyNameBuilder;

	string dateStr = "";
	string id ="";
	string eType ="";
	string num="";
	double price;
	try{
		// Get event date
		dateKeyNameBuilder << "EVENT" << currConfFileIndex<< ".Date";
		dateStr = getString(dateKeyNameBuilder.str());

		// Get event date
		userIdKeyNameBuilder << "EVENT" << currConfFileIndex<< ".UserID";
		id = getString(userIdKeyNameBuilder.str());

		// Get event date
		energyTypeKeyNameBuilder << "EVENT" << currConfFileIndex<< ".EnergyType";
		eType = getString(energyTypeKeyNameBuilder.str());

		// Get event date
		numOfUnitsKeyNameBuilder << "EVENT" << currConfFileIndex<< ".NumberOfUnits";
		num = getString(numOfUnitsKeyNameBuilder.str());

		// Get event date
		priceKeyNameBuilder << "EVENT" << currConfFileIndex<< ".PricePerUnit";
		price = getDouble(priceKeyNameBuilder.str());

		isValid = true;
	}
	catch (NotFoundException ex)
    {
    	cout << ex.displayText() << "\n";
    }

	// Parse the date
	DateTime  * date = new Poco::DateTime();
	if (isValid){
		int timeZoneDiff;
		if (!DateTimeParser::tryParse("%d/%n/%Y", dateStr, *date, timeZoneDiff)){
			// Failed to parse date. quit.
			isValid = false;
		}

	}

	int intId = atoi(id.c_str());
	int intNum = atoi(num.c_str());

	ass2::eUser checkName = ass2::Id2eUser(intId);
	ass2::eEnergy checkEnergy = ass2::stringToEnrgy(eType);
	if (checkName == ass2::eNoUser | checkEnergy == ass2::noEnergy){
		isValid = false;
	}



	string key = string();
	key = "EVENT";
	int i = currConfFileIndex;
	string s;
	stringstream out;
	out << i;
	s = out.str();
	key += s;
	Keys range = Keys();
	keys(key, range);
	if (range.size() > 6 | price <=0  | intNum<=0)
		isValid = false;


	if (isValid){
		SellEvent* event = new SellEvent(date, intNum, intId, ass2::stringToEnrgy(eType), price);
		events.push_back(event);
	}
	else{
			delete date;
		}

}
void CEventsConfiguration::readNcreateBuy(int currConfFileIndex){
		bool isValid = false;

		ostringstream dateKeyNameBuilder;
		ostringstream userIdKeyNameBuilder;
		ostringstream energyTypeKeyNameBuilder;
		ostringstream numOfUnitsKeyNameBuilder;
		ostringstream priceKeyNameBuilder;

		string dateStr = "";
		string id ="";
		string eType ="";
		string num="";
		double price;
		try{
			// Get event date
			dateKeyNameBuilder << "EVENT" << currConfFileIndex<< ".Date";
			dateStr = getString(dateKeyNameBuilder.str());

			// Get event date
			userIdKeyNameBuilder << "EVENT" << currConfFileIndex<< ".UserID";
			id = getString(userIdKeyNameBuilder.str());

			// Get event date
			energyTypeKeyNameBuilder << "EVENT" << currConfFileIndex<< ".EnergyType";
			eType = getString(energyTypeKeyNameBuilder.str());

			// Get event date
			numOfUnitsKeyNameBuilder << "EVENT" << currConfFileIndex<< ".NumberOfUnits";
			num = getString(numOfUnitsKeyNameBuilder.str());

			// Get event date
			priceKeyNameBuilder << "EVENT" << currConfFileIndex<< ".PricePerUnit";
			price = getDouble(priceKeyNameBuilder.str());

			isValid = true;
		}
		catch (NotFoundException ex)
	    {
	    	cout << ex.displayText() << "\n";
	    }

		// Parse the date
		DateTime *date= new Poco::DateTime();
		if (isValid){
			int timeZoneDiff;
			if (!DateTimeParser::tryParse("%d/%n/%Y", dateStr, *date, timeZoneDiff)){
				// Failed to parse date. quit.
				isValid = false;
			}

		}

		int intId = atoi(id.c_str());
		int intNum = atoi(num.c_str());

		ass2::eUser checkName = ass2::Id2eUser(intId);
		ass2::eEnergy checkEnergy = ass2::stringToEnrgy(eType);
		if (checkName == ass2::eNoUser | checkEnergy == ass2::noEnergy){
			isValid = false;
		}

		string key = string();
		key = "EVENT";
		int i = currConfFileIndex;
		string s;
		stringstream out;
		out << i;
		s = out.str();
		key += s;
		Keys range = Keys();
		keys(key, range);
		if (range.size() > 6 | price <=0 | intNum<=0)
			isValid = false;




		if (isValid){
			BuyEvent* event = new BuyEvent(date, intNum, intId, ass2::stringToEnrgy(eType), price);
			events.push_back(event);
		}
		else{
				delete date;
			}

}
void CEventsConfiguration::readNcreateUserReport(int currConfFileIndex){
			bool isValid = false;

			ostringstream dateKeyNameBuilder;
			ostringstream userIdKeyNameBuilder;


			string dateStr = "";
			string id ="";

			try{
				// Get event date
				dateKeyNameBuilder << "EVENT" << currConfFileIndex<< ".Date";
				dateStr = getString(dateKeyNameBuilder.str());

				// Get event date
				userIdKeyNameBuilder << "EVENT" << currConfFileIndex<< ".UserID";
				id = getString(userIdKeyNameBuilder.str());

				isValid = true;
			}
			catch (NotFoundException ex)
		    {
		    	cout << ex.displayText() << "\n";
		    }

			// Parse the date
			DateTime * date = new Poco::DateTime();
			if (isValid){
				int timeZoneDiff;
				if (!DateTimeParser::tryParse("%d/%n/%Y", dateStr, *date, timeZoneDiff)){
					// Failed to parse date. quit.
					isValid = false;
				}

			}

			int intId = atoi(id.c_str());

			ass2::eUser checkName = ass2::Id2eUser(intId);
			if (checkName == ass2::eNoUser){
				isValid = false;
			}



			string key = string();
			key = "EVENT";
			int i = currConfFileIndex;
			string s;
			stringstream out;
			out << i;
			s = out.str();
			key += s;
			Keys range = Keys();
			keys(key, range);
			if (range.size() > 3)
				isValid = false;


			if (isValid){
				UserReport* event = new UserReport(date, intId);
				events.push_back(event);
			}
			else{
					delete date;
				}

}
void CEventsConfiguration::readNcreateEnergyReport(int currConfFileIndex){
	bool isValid = false;

	ostringstream dateKeyNameBuilder;


	string dateStr = "";

	try{
		// Get event date
		dateKeyNameBuilder << "EVENT" << currConfFileIndex<< ".Date";
		dateStr = getString(dateKeyNameBuilder.str());

		isValid = true;
	}
	catch (NotFoundException ex)
    {
    	cout << ex.displayText() << "\n";
    }

	// Parse the date
	DateTime *date =  new Poco::DateTime();
	if (isValid){
		int timeZoneDiff;
		if (!DateTimeParser::tryParse("%d/%n/%Y", dateStr, *date, timeZoneDiff)){
			// Failed to parse date. quit.
			isValid = false;
		}

	}

	string key = string();
	key = "EVENT";
	int i = currConfFileIndex;
	string s;
	stringstream out;
	out << i;
	s = out.str();
	key += s;
	Keys range = Keys();
	keys(key, range);
	if (range.size() > 2)
		isValid = false;

	if (isValid){
		EnergyReport* event = new EnergyReport(date);
		events.push_back(event);
	}
	else{
			delete date;
		}

}
void CEventsConfiguration::readNcreateAccountReport(int currConfFileIndex){
	bool isValid = false;

	ostringstream dateKeyNameBuilder;
	ostringstream userIdKeyNameBuilder;


	string dateStr = "";
	string id ="";

	try{
		// Get event date
		dateKeyNameBuilder << "EVENT" << currConfFileIndex<< ".Date";
		dateStr = getString(dateKeyNameBuilder.str());

		// Get event date
		userIdKeyNameBuilder << "EVENT" << currConfFileIndex<< ".UserID";
		id = getString(userIdKeyNameBuilder.str());

		isValid = true;
	}
	catch (NotFoundException ex)
    {
    	cout << ex.displayText() << "\n";
    }

	// Parse the date
	DateTime* date = new Poco::DateTime();
	if (isValid){
		int timeZoneDiff;
		if (!DateTimeParser::tryParse("%d/%n/%Y", dateStr, *date, timeZoneDiff)){
			// Failed to parse date. quit.
			isValid = false;
		}

	}

	int intId = atoi(id.c_str());

	ass2::eUser checkName = ass2::Id2eUser(intId);
	if (checkName == ass2::eNoUser){
		isValid = false;
	}



	string key = string();
	key = "EVENT";
	int i = currConfFileIndex;
	string s;
	stringstream out;
	out << i;
	s = out.str();
	key += s;
	Keys range = Keys();
	keys(key, range);
	if (range.size() > 3)
		isValid = false;



	if (isValid){
		AccountReport* event = new AccountReport(date, intId);
		events.push_back(event);
	}
	else{
			delete date;
		}

}
void CEventsConfiguration::readNcreateProfitReport(int currConfFileIndex){
	bool isValid = false;

	ostringstream dateKeyNameBuilder;
	ostringstream userIdKeyNameBuilder;


	string dateStr = "";
	string id ="";

	try{
		// Get event date
		dateKeyNameBuilder << "EVENT" << currConfFileIndex<< ".Date";
		dateStr = getString(dateKeyNameBuilder.str());

		// Get event date
		userIdKeyNameBuilder << "EVENT" << currConfFileIndex<< ".UserID";
		id = getString(userIdKeyNameBuilder.str());

		isValid = true;
	}
	catch (NotFoundException ex)
    {
    	cout << ex.displayText() << "\n";
    }

	// Parse the date
	DateTime* date = new Poco::DateTime();
	if (isValid){
		int timeZoneDiff;
		if (!DateTimeParser::tryParse("%d/%n/%Y", dateStr, *date, timeZoneDiff)){
			// Failed to parse date. quit.
			isValid = false;
		}

	}

	int intId = atoi(id.c_str());

	ass2::eUser checkName = ass2::Id2eUser(intId);
	if (checkName == ass2::eNoUser){
		isValid = false;
	}


	string key = string();
	key = "EVENT";
	int i = currConfFileIndex;
	string s;
	stringstream out;
	out << i;
	s = out.str();
	key += s;
	Keys range = Keys();
	keys(key, range);
	if (range.size() > 3)
		isValid = false;


	if (isValid){
		ProfitReport* event = new ProfitReport(date, intId);
		events.push_back(event);
	}
	else{
			delete date;
		}

}
void CEventsConfiguration::readNcreateActivityReport(int currConfFileIndex){
	bool isValid = false;

	ostringstream dateKeyNameBuilder;
	ostringstream userIdKeyNameBuilder;


	string dateStr = "";
	string id ="";

	try{
		// Get event date
		dateKeyNameBuilder << "EVENT" << currConfFileIndex<< ".Date";
		dateStr = getString(dateKeyNameBuilder.str());

		// Get event date
		userIdKeyNameBuilder << "EVENT" << currConfFileIndex<< ".UserID";
		id = getString(userIdKeyNameBuilder.str());

		isValid = true;
	}
	catch (NotFoundException ex)
    {
    	cout << ex.displayText() << "\n";
    }

	// Parse the date
	DateTime *date = new Poco::DateTime();
	if (isValid){
		int timeZoneDiff;
		if (!DateTimeParser::tryParse("%d/%n/%Y", dateStr, *date, timeZoneDiff)){
			// Failed to parse date. quit.
			isValid = false;
		}

	}

	int intId = atoi(id.c_str());

	ass2::eUser checkName = ass2::Id2eUser(intId);
	if (checkName == ass2::eNoUser){
		isValid = false;
	}



	string key = string();
	key = "EVENT";
	int i = currConfFileIndex;
	string s;
	stringstream out;
	out << i;
	s = out.str();
	key += s;
	Keys range = Keys();
	keys(key, range);
	if (range.size() > 3)
		isValid = false;


	if (isValid){
		ActivityReport* event = new ActivityReport(date, intId);
		events.push_back(event);
	}
	else{
			delete date;
		}

}

